﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Input;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;

namespace CredentialsManager.ViewModels
{
    public class CreateRoleViewModel : ViewModelBase
    {
        #region Private classes

        private class WorkerInput
        {
            public string Role { get; set; }
            public string Application { get; set; }
        }

        #endregion

        #region Private member variables

        private string m_Application;
        private string m_Role;
        private ReadOnlyCollection<string> m_NewRoles;
        private ICommand m_CreateCommand;
        private BackgroundWorker m_CreateWorker;

        #endregion

        #region Constructors

        public CreateRoleViewModel(string application)
            : this(Resources.RoleViewModelDefaultDisplayName, application)
        { }

        public CreateRoleViewModel(string displayName, string application)
        {
            this.DisplayName = displayName;
            this.Application = application;
            m_NewRoles = new ReadOnlyCollection<string>(new List<string>());

            m_CreateWorker = new BackgroundWorker();
            m_CreateWorker.DoWork += m_CreateWorker_DoWork;
            m_CreateWorker.RunWorkerCompleted += m_CreateWorker_RunWorkerCompleted;
        }

        #endregion

        #region Background worker handlers

        private void m_CreateWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var input = e.Argument as WorkerInput;
            Debug.Assert(input != null);

            var proxy = ProxyFactory.Create<RoleManagerClient, IRoleManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                proxy.CreateRole(input.Application, input.Role);
            }
            finally
            {
                ProxyFactory.Cleanup<RoleManagerClient, IRoleManager>(proxy);
            }
        }

        private void m_CreateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }
            else
            {
                var newRoles = new List<string>(this.NewRoles);
                newRoles.Add(this.Role);
                this.NewRoles = new ReadOnlyCollection<string>(newRoles);
                this.Role = string.Empty;
            }

            this.IsLoading = false;
        }

        #endregion

        #region Public properties

        public string Application
        {
            get
            {
                return m_Application;
            }
            private set
            {
                m_Application = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public string Role
        {
            get
            {
                return m_Role;
            }
            set
            {
                m_Role = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
                RaisePropertyChanged("IsValid");
            }
        }

        public ReadOnlyCollection<string> NewRoles
        {
            get
            {
                return m_NewRoles;
            }
            set
            {
                m_NewRoles = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public bool IsValid
        {
            get
            {
                return (this.Role != null && this.Role.Trim() != string.Empty);
            }
        }

        #endregion

        #region Private methods

        private void Create()
        {
            if (!this.IsValid)
            {
                throw new InvalidOperationException(Resources.InvalidRoleNameErrorMessage);
            }

            var input = new WorkerInput() { 
                Application = this.Application, Role = this.Role };

            this.IsLoading = true;
            m_CreateWorker.RunWorkerAsync(input);
        }

        #endregion

        #region Commands

        public ICommand CreateCommand
        {
            get
            {
                return m_CreateCommand ?? (m_CreateCommand = new RelayCommand(
                    param => this.Create()));
            }
        }

        #endregion
    }
}
